/**
 *  Image Manipulation Plugin Version 1.0
 *  Bhaktavatsalam Nallanthighal
 *  October 2010
 *  Educational Networks Inc.
 *  
 *  Parameters:
 *      1. viewportID: The existing div inside which the image manipulation tool has to be created
 *	    2. width: Width of the viewport in pixels.
 *         Default: 300
 *      3. height: Height of the viewport in pixels.
 *         Default: 250
 *      4. image: The path to the image to be loaded into the image manipulation tool
 *      5. x: The positive horizontal coordinate at which the image should initially be shown
 *         Default: 0
 *      6. y: The positive vertical coordinate at which the image should initially be shown 
 *         Default: 0
 *      7. zoomedWidth: The zoomed width with which the image should initially be shown. The height will automatically be calculated using the aspect ratio of the image
 *         Default: The natural width of the loaded image.
 *      8. onPan: A handler that is fired when the image in the container is panned. The zoomed width, left and top positions are sent as arguments.
 *      9. onZoom: A handler that is fired when the image in the container is zoomed. The zoomed width, left and top positions are sent as arguments.
 *      10. onLoad: A handler that is fired when the image has been loaded in the container. The natural width and height of loaded image are sent as arguments.
 *      11. doMagnify: A handler that is fired when the user tries to magnify the image by click-and-drag, double click or mouse scroll. The target imageID and drift amount are sent as arguments. 
 * 
 *  Notes:
 *      - IT_viewport_container is for CSS styling of viewport container
 *      - IT_viewport is for CSS styling of viewport
 *      - IT_image is for CSS styling of the actual image itself
 */

var IMP = {
	initialize : function(params) {
		IMP._dragStart = null;
		IMP._onPan = params.onPan;
		IMP._onZoom = params.onZoom;
		IMP._doMagnify = params.doMagnify;
		params.x = params.x ? (-1 * IMP.Utils.toInteger(params.x)) : 0;
		params.y = params.y ? (-1 * IMP.Utils.toInteger(params.y)) : 0;
		if(!params.width) {
			params.width = 300;
		}
		if(!params.height) {
			params.height = 250;
		}
		
		var innerImage = document.createElement("img");
		innerImage.onload = function(e) { 
			innerImage.setAttribute("originalWidth", IMP.Utils.toInteger(innerImage.offsetWidth || innerImage.width) + "px");
			innerImage.setAttribute("originalHeight", IMP.Utils.toInteger(innerImage.offsetHeight || innerImage.height) + "px");
			if(params.onLoad) {
				params.onLoad(innerImage.getAttribute("originalWidth"), innerImage.getAttribute("originalHeight"));
			}
			if(!params.zoomedWidth)
				params.zoomedWidth = innerImage.getAttribute("originalWidth");
			
			innerImage.setAttribute("id", params.viewportID + "-img");
			innerImage.className += " IT_image";
			innerImage.style.width = IMP.Utils.toInteger(params.zoomedWidth) + "px";
			innerImage.style.height = IMP.Utils.toInteger(IMP.Utils.toInteger(params.zoomedWidth) * IMP.Utils.toInteger(innerImage.getAttribute("originalHeight")) / IMP.Utils.toInteger(innerImage.getAttribute("originalWidth"))) + "px";
			innerImage.style.left = params.x + "px"; 
			innerImage.style.top = params.y + "px";

			var viewportContainerObj = document.getElementById(params.viewportID);
			viewportContainerObj.className += " IT_viewport_container";
			viewportContainerObj.style.cssText = "width:" + IMP.Utils.toInteger(params.width) + "px; height:" + IMP.Utils.toInteger(params.height) + "px;";
			
			var viewportObj = document.createElement("div");
			viewportObj.setAttribute("id", params.viewportID + "-img-div");
			viewportObj.className += " IT_viewport";
			viewportObj.style.cssText += "; width:" + IMP.Utils.toInteger(params.width) + "px; height:" + IMP.Utils.toInteger(params.height) + "px;";
			viewportObj.appendChild(innerImage);

			while(viewportContainerObj.hasChildNodes()) {
				viewportContainerObj.removeChild(viewportContainerObj.lastChild);
			}
			viewportContainerObj.appendChild(viewportObj);
		};
		innerImage.src = params.image;
		
		innerImage.onmousedown = function(e) {
			e = e || window.event;
			IMP._dragStart = IMP.Utils.getMouseCoordinates(e);
			return false;
		};
		
		innerImage.onmousemove = function(e) {
			e = e || window.event;
			
			document.body.style.cursor = (e.altKey || e.ctrlKey || e.shiftKey) ? "url('/apps/pics/magnify.cur'), all-scroll" : "move";
			
			if(IMP._dragStart) {
				var mousepos = IMP.Utils.getMouseCoordinates(e);
				
				if(e.altKey || e.ctrlKey || e.shiftKey) {
					IMP.doMagnify(e.target ? e.target.id : e.srcElement.id, 
						(Math.max((mousepos.x - IMP._dragStart.x), (mousepos.y - IMP._dragStart.y))>0 ? -1 : 1) * 20);
				}
				else {
					IMP.pan(e.target ? e.target.id : e.srcElement.id, (mousepos.x - IMP._dragStart.x), (mousepos.y - IMP._dragStart.y));
				}
				
				IMP._dragStart = mousepos;
			}			
			return false;
		};	
		
		innerImage.onmouseup = function(e) {
			e = e || window.event;
			
			if(IMP._dragStart) {
				var mousepos = IMP.Utils.getMouseCoordinates(e);
				IMP.pan(e.target ? e.target.id : e.srcElement.id, (mousepos.x - IMP._dragStart.x), (mousepos.y - IMP._dragStart.y));
				IMP._dragStart = null;
			}
			return false;
		};
		
		innerImage.onmouseout = function(e) { 
			IMP._dragStart = null;
			IMP._doZoom = false;
			document.body.style.cursor = "default";
			return true; 
		};
		
		innerImage.onmouseover = function(e) {
			e = e || window.event;
			if(e) {
				IMP._doZoom = true;
				document.body.style.cursor = (e.altKey || e.ctrlKey || e.shiftKey) ? "url('/apps/pics/magnify.cur'), all-scroll" : "move";
			}
			return false;
		};
		
		innerImage.ondblclick = function(e) {
			e = e || window.event;			
			IMP.doMagnify(e.target ? e.target.id : e.srcElement.id, (e.altKey || e.ctrlKey || e.shiftKey) ? -100 : 100);
			return false;	
		}
		
		onMouseScroll = function(e) {
			e = e || window.event;
			
			if(IMP._doZoom) {
				if(IMP.doMagnify(e.target ? e.target.id : e.srcElement.id, 
					(e.wheelDelta ? (e.wheelDelta / 120) : (e.detail ? (-e.detail / 3) : 0))>0 ? 20 : -20)) {
					if(e.preventDefault)
						e.preventDefault();
					e.returnValue = false;
					return false;
				}
			}			
			return true;
		};
		
		if(window.addEventListener) {
			window.addEventListener("DOMMouseScroll", onMouseScroll, false);
		}
		window.onmousewheel = document.onmousewheel = onMouseScroll;
		
	},
	
	pan : function(imageID, xOffset, yOffset) {
		if(imageID) {
			document.getElementById(imageID).style.left = IMP.Utils.toInteger(document.getElementById(imageID).style.left) + xOffset + "px";
			document.getElementById(imageID).style.top = IMP.Utils.toInteger(document.getElementById(imageID).style.top) + yOffset + "px";
			
			IMP.fit(imageID);
			
			if(IMP._onPan) {
				IMP._onPan(document.getElementById(imageID).offsetWidth, -1 * IMP.Utils.toInteger(document.getElementById(imageID).style.left), -1 * IMP.Utils.toInteger(document.getElementById(imageID).style.top));
			}
		}
	},
	
	zoom : function(viewportID, zoomedWidth) {
		var image = document.getElementById(viewportID + "-img");
		if(image) {
			var imageContainer = document.getElementById(viewportID + "-img-div");
			
			var newWidth = IMP.Utils.toInteger(zoomedWidth);
			var newHeight = IMP.Utils.toInteger((newWidth / IMP.Utils.toInteger(image.getAttribute("originalWidth"))) * IMP.Utils.toInteger(image.getAttribute("originalHeight")));
			
			/* Center the position of the center in relation to the visible area of the image in the viewport */
			var centerX = IMP.Utils.toInteger(image.style.width) / (-1 * IMP.Utils.toInteger(image.style.left) + IMP.Utils.toInteger(imageContainer.style.width)/2);
			var centerY = IMP.Utils.toInteger(image.style.height) / (-1 * IMP.Utils.toInteger(image.style.top) + IMP.Utils.toInteger(imageContainer.style.height)/2); 
			
			/* Use the relative centers to calculate new center and set the left. top to make it the center */
			image.style.left = IMP.Utils.toInteger(image.style.left) - ((newWidth - IMP.Utils.toInteger(image.style.width)) / centerX) + "px";
			image.style.top = IMP.Utils.toInteger(image.style.top) - ((newHeight - IMP.Utils.toInteger(image.style.height)) / centerY) + "px";
			
			image.style.width = IMP.Utils.toInteger(newWidth) + "px";
			image.style.height = IMP.Utils.toInteger(newHeight) + "px";

			IMP.fit(viewportID + "-img");
			
			if(IMP._onZoom) {
				IMP._onZoom(image.offsetWidth, -1 * IMP.Utils.toInteger(image.style.left), -1 * IMP.Utils.toInteger(image.style.top));
			}
		}
	},
	
	fit : function(imageID) {
		var image = document.getElementById(imageID);
		var imageContainer = document.getElementById(imageID + "-div");
	
		if(IMP.Utils.toInteger(image.style.left)<(-1 * (IMP.Utils.toInteger(image.style.width) - IMP.Utils.toInteger(imageContainer.style.width)))) {
			image.style.left = (-1 * (IMP.Utils.toInteger(image.style.width) - IMP.Utils.toInteger(imageContainer.style.width))) + "px";
		}
		if(IMP.Utils.toInteger(image.style.top)<(-1 * (IMP.Utils.toInteger(image.style.height) - IMP.Utils.toInteger(imageContainer.style.height)))) {
			image.style.top = (-1 * (IMP.Utils.toInteger(image.style.height) - IMP.Utils.toInteger(imageContainer.style.height))) + "px";
		}
		if(IMP.Utils.toInteger(image.style.left)>0) {
			image.style.left = "0px";
		}
		if(IMP.Utils.toInteger(image.style.top)>0) {
			image.style.top = "0px";
		}
	},
	
	doMagnify : function(imageID, zoomAmount) {
		if(IMP._doMagnify) {
			return IMP._doMagnify(imageID.split("-")[0], IMP.Utils.toInteger(document.getElementById(imageID).style.width) + IMP.Utils.toInteger(zoomAmount));
		}
		return IMP.zoom(imageID.split("-")[0], IMP.Utils.toInteger(document.getElementById(imageID).style.width) + IMP.Utils.toInteger(zoomAmount));
	},
	
	Utils: {
		toInteger : function(val) {
			return parseInt(val, 10);
		},
		
		getMouseCoordinates : function(e) {
			e = e || window.event;
			
			/* Non-IE browsers */
			if(e.pageX || e.pageY) { 
				return {x: e.pageX, y: e.pageY};
			}
				
			/* IE */	
			return {x: e.clientX + document.body.scrollLeft - document.body.clientLeft,
				y: e.clientY + document.body.scrollTop - document.body.clientTop};
		}
	}
};